home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / popen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-08  |  4.6 KB  |  241 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)popen.c    5.13 (Berkeley) 7/8/88";
  20. #endif /* not lint */
  21.  
  22. #include "rcv.h"
  23. #include <sys/signal.h>
  24. #include <sys/wait.h>
  25.  
  26. #define READ 0
  27. #define WRITE 1
  28. static int *pid;
  29.  
  30. FILE *
  31. Popen(cmd, mode)
  32.     char *cmd;
  33.     char *mode;
  34. {
  35.     int p[2];
  36.     int myside, hisside, fd0, fd1;
  37.  
  38.     if (pid == 0)
  39.         pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize());
  40.     if (pipe(p) < 0)
  41.         return NULL;
  42.     if (*mode == 'r') {
  43.         myside = p[READ];
  44.         fd0 = -1;
  45.         hisside = fd1 = p[WRITE];
  46.     } else {
  47.         myside = p[WRITE];
  48.         hisside = fd0 = p[READ];
  49.         fd1 = -1;
  50.     }
  51.     if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) {
  52.         close(p[READ]);
  53.         close(p[WRITE]);
  54.         return NULL;
  55.     }
  56.     close(hisside);
  57.     return fdopen(myside, mode);
  58. }
  59.  
  60. Pclose(ptr)
  61.     FILE *ptr;
  62. {
  63.     int i;
  64.     int omask;
  65.  
  66.     i = fileno(ptr);
  67.     fclose(ptr);
  68.     omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
  69.     i = wait_child(pid[i]);
  70.     sigsetmask(omask);
  71.     return i;
  72. }
  73.  
  74. /*
  75.  * Run a command without a shell, with optional arguments and splicing
  76.  * of stdin and stdout.  The command name can be a sequence of words.
  77.  * Signals must be handled by the caller.
  78.  * "Mask" contains the signals to ignore in the new process.
  79.  * SIGINT is enabled unless it's in the mask.
  80.  */
  81. /*VARARGS4*/
  82. run_command(cmd, mask, infd, outfd, a0, a1, a2)
  83.     char *cmd;
  84.     int mask, infd, outfd;
  85.     char *a0, *a1, *a2;
  86. {
  87.     int pid;
  88.  
  89.     if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
  90.         return -1;
  91.     return wait_command(pid);
  92. }
  93.  
  94. /*VARARGS4*/
  95. start_command(cmd, mask, infd, outfd, a0, a1, a2)
  96.     char *cmd;
  97.     int mask, infd, outfd;
  98.     char *a0, *a1, *a2;
  99. {
  100.     int pid;
  101.  
  102.     if ((pid = vfork()) < 0) {
  103.         perror("fork");
  104.         return -1;
  105.     }
  106.     if (pid == 0) {
  107.         char *argv[100];
  108.         int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
  109.  
  110.         if ((argv[i++] = a0) != NOSTR &&
  111.             (argv[i++] = a1) != NOSTR &&
  112.             (argv[i++] = a2) != NOSTR)
  113.             argv[i] = NOSTR;
  114.         prepare_child(mask, infd, outfd);
  115.         execvp(argv[0], argv);
  116.         perror(argv[0]);
  117.         _exit(1);
  118.     }
  119.     return pid;
  120. }
  121.  
  122. prepare_child(mask, infd, outfd)
  123.     int mask, infd, outfd;
  124. {
  125.     int i;
  126.  
  127.     if (infd >= 0)
  128.         dup2(infd, 0);
  129.     if (outfd >= 0)
  130.         dup2(outfd, 1);
  131.     for (i = getdtablesize(); --i > 2;)
  132.         close(i);
  133.     for (i = 1; i <= NSIG; i++)
  134.         if (mask & sigmask(i))
  135.             (void) signal(i, SIG_IGN);
  136.     if ((mask & sigmask(SIGINT)) == 0)
  137.         (void) signal(SIGINT, SIG_DFL);
  138.     (void) sigsetmask(0);
  139. }
  140.  
  141. wait_command(pid)
  142.     int pid;
  143. {
  144.  
  145.     if (wait_child(pid) < 0) {
  146.         printf("Fatal error in process.\n");
  147.         return -1;
  148.     }
  149.     return 0;
  150. }
  151.  
  152. struct child {
  153.     int pid;
  154.     char done;
  155.     char free;
  156.     union wait status;
  157.     struct child *link;
  158. };
  159. static struct child *child;
  160.  
  161. struct child *
  162. findchild(pid)
  163.     int pid;
  164. {
  165.     register struct child **cpp;
  166.  
  167.     for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
  168.          cpp = &(*cpp)->link)
  169.             ;
  170.     if (*cpp == NULL) {
  171.         *cpp = (struct child *) malloc(sizeof (struct child));
  172.         (*cpp)->pid = pid;
  173.         (*cpp)->done = (*cpp)->free = 0;
  174.         (*cpp)->link = NULL;
  175.     }
  176.     return *cpp;
  177. }
  178.  
  179. delchild(cp)
  180.     register struct child *cp;
  181. {
  182.     register struct child **cpp;
  183.  
  184.     for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
  185.         ;
  186.     *cpp = cp->link;
  187.     free((char *) cp);
  188. }
  189.  
  190. sigchild()
  191. {
  192.     int pid;
  193.     union wait status;
  194.     register struct child *cp;
  195.  
  196.     while ((pid = wait3(&status, WNOHANG, (struct timeval *)0)) > 0) {
  197.         cp = findchild(pid);
  198.         if (cp->free)
  199.             delchild(cp);
  200.         else {
  201.             cp->done = 1;
  202.             cp->status = status;
  203.         }
  204.     }
  205. }
  206.  
  207. union wait wait_status;
  208.  
  209. /*
  210.  * Wait for a specific child to die.
  211.  */
  212. wait_child(pid)
  213.     int pid;
  214. {
  215.     int mask = sigblock(sigmask(SIGCHLD));
  216.     register struct child *cp = findchild(pid);
  217.  
  218.     while (!cp->done)
  219.         sigpause(mask);
  220.     wait_status = cp->status;
  221.     delchild(cp);
  222.     sigsetmask(mask);
  223.     return wait_status.w_status ? -1 : 0;
  224. }
  225.  
  226. /*
  227.  * Mark a child as don't care.
  228.  */
  229. free_child(pid)
  230.     int pid;
  231. {
  232.     int mask = sigblock(sigmask(SIGCHLD));
  233.     register struct child *cp = findchild(pid);
  234.  
  235.     if (cp->done)
  236.         delchild(cp);
  237.     else
  238.         cp->free = 1;
  239.     sigsetmask(mask);
  240. }
  241.